// 6.5.2 特殊用途语言特性：内联函数和constexpr函数
/**
 * 三种函数相关的语言特性，这些特性对大多数程序都有用，它们分别是：
 * 1. 默认实参
 * 2. 内联函数
 * 3. constexpr函数
 */
#include <iostream>
#include <initializer_list>
#include <iterator>
#include <vector>
using std::begin, std::end;
using std::cin, std::cout, std::endl;
using std::initializer_list;
using std::string;
using std::vector;

// 内联函数可避免函数调用的开销
// 例如：cout << shorterString(s1,s2) << endl; 假设shorterString是内联函数
// 则变成了： cout << (s1.size() > s2.size() ? s2 : s1) << endl;
// 从而消除了shorterString函数的运行时开销。
inline const string &shorterString(const string &s1,const string &s2);

// constexpr函数
// 是指能用于常量表达式（参见2.4.4节，第58页）的函数。
//定义constexpr函数的方法与其他函数类似，不过要遵循几项约定：
// 1. 函数的返回类型及所有形参的类型都得是字面值类型（参见2.4.4节，第59页）
// 2. 而且函数体中必须有且只有一条return语句
constexpr int new_size() {return 42;}
constexpr int foo = new_size(); // 执行该初始化任务时，编译器把对constexpr函数的调用替换成其结果值。
// 为了能在编译过程中随时展开，constexpr函数被隐式地指定为内联函数。

// 我们允许constexpr函数的返回值并非一个常量
constexpr size_t scale(size_t cnt) { return new_size() * cnt;}

int main(int argc, char const *argv[])
{
    // 当一个constexpr函数的实参是常量表达式时，它的返回值也是常量表达式；反之则不然
    int arr[scale(2)]; // 正确，scale(2)是常量表达式
    int i = 2;
    int arr1[scale(i)]; // 错误，scale(i)不是常量表达式

    return 0;
}

inline const string &shorterString(const string &s1,const string &s2)
{
    return s1.size() > s2.size() ? s2 : s1;
}